﻿#region Copyright(C) 2018 FI Ltd. All rights reserved.

// ==================================================================================================
// Copyright(C) 2018 FI Ltd. All rights reserved.
//
// SYSTEM NAME	:   FI.Net Application Framework 
// COMPONENT ID :   FI.EntityFramework
// COMPONENT DESC:  
//
// CREATED DATE/BY: 18 Aug 2018 / Tian Mi
//
// REVISION HISTORY:	DATE/BY			SR#/CS/PM#/OTHERS		DESCRIPTION OF CHANGE
// ==================================================================================================

#endregion

using FI.Core.Utilities;
using System;
using System.Data.Common;
using System.Data.Entity;
using System.Data.Entity.Infrastructure.Interception;
using System.Diagnostics;
using System.Linq;
using System.Text;

namespace FI.EntityFramework.Interception
{
    /// <summary>
    /// This class that implements <see cref="IDbCommandInterceptor" /> to reset delete command.
    /// </summary>
    public class DbCommandInterceptor : IDbCommandInterceptor
    {
        private DbContext context;

        /// <summary>
        /// Initializes a new instance of the <see cref="DbCommandInterceptor"/> class.
        /// </summary>
        /// <param name="dbContext">The database context.</param>
        public DbCommandInterceptor(DbContext dbContext)
        {
            Guard.ArgumentNotNull(dbContext, "dbContext");

            this.context = dbContext;

           
        }

        /// <summary>
        /// This method is called after a call to 
        /// <see cref="M:System.Data.Common.DbCommand.ExecuteNonQuery" />  or
        ///             one of its async counterparts is made. This method should return the given result.
        ///             However, the result used by Entity Framework can be changed by returning a different value.
        /// </summary>
        /// <param name="command">The command being executed.</param>
        /// <param name="interceptionContext">Contextual information associated with the call.</param>
        /// <remarks>
        /// For async operations this method is not called until after the async task has completed
        ///             or failed.
        /// </remarks>
        public void NonQueryExecuted(DbCommand command, DbCommandInterceptionContext<int> interceptionContext)
        {
        }

        /// <summary>
        /// This method is called before a call to 
        /// <see cref="M:System.Data.Common.DbCommand.ExecuteNonQuery" /> or
        ///             one of its async counterparts is made.
        /// </summary>
        /// <param name="command">The command being executed.</param>
        /// <param name="interceptionContext">Contextual information associated with the call.</param>
        public void NonQueryExecuting(DbCommand command, DbCommandInterceptionContext<int> interceptionContext)
        {
            if (!interceptionContext.DbContexts.Contains(this.context)) { return; }

            var helper = DbCommandHelperFactory.Create(command);
            if (helper.ValidateDeleteCommand())
            {
                helper.ResetDeleteCommand(this.context);
            }
        }

        /// <summary>
        /// This method is called after a call to 
        /// <see cref="M:System.Data.Common.DbCommand.ExecuteReader(System.Data.CommandBehavior)" />  or
        ///             one of its async counterparts is made. This method should return the given result. However, the
        ///             result used by Entity Framework can be changed by returning a different value.
        /// </summary>
        /// <param name="command">The command being executed.</param>
        /// <param name="interceptionContext">Contextual information associated with the call.</param>
        /// <remarks>
        /// For async operations this method is not called until after the async task has completed
        ///             or failed.
        /// </remarks>
        public void ReaderExecuted(DbCommand command, DbCommandInterceptionContext<DbDataReader> interceptionContext)
        {
        }

        /// <summary>
        /// This method is called before a call to 
        /// <see cref="M:System.Data.Common.DbCommand.ExecuteReader(System.Data.CommandBehavior)" />  or
        ///             one of its async counterparts is made.
        /// </summary>
        /// <param name="command">The command being executed.</param>
        /// <param name="interceptionContext">Contextual information associated with the call.</param>
        public void ReaderExecuting(DbCommand command, DbCommandInterceptionContext<DbDataReader> interceptionContext)
        {
        }

        /// <summary>
        /// This method is called after a call to 
        /// <see cref="M:System.Data.Common.DbCommand.ExecuteScalar" />  or
        ///             one of its async counterparts is made. This method should return the given result.
        ///             However, the result used by Entity Framework can be changed by returning a different value.
        /// </summary>
        /// <param name="command">The command being executed.</param>
        /// <param name="interceptionContext">Contextual information associated with the call.</param>
        /// <remarks>
        /// For async operations this method is not called until after the async task has completed
        ///             or failed.
        /// </remarks>
        public void ScalarExecuted(DbCommand command, DbCommandInterceptionContext<object> interceptionContext)
        {
        }

        /// <summary>
        /// This method is called before a call to 
        /// <see cref="M:System.Data.Common.DbCommand.ExecuteScalar" />  or
        ///             one of its async counterparts is made.
        /// </summary>
        /// <param name="command">The command being executed.</param>
        /// <param name="interceptionContext">Contextual information associated with the call.</param>
        public void ScalarExecuting(DbCommand command, DbCommandInterceptionContext<object> interceptionContext)
        {
        }


        //private readonly Stopwatch _stopwatch = new Stopwatch();
        //public override void ScalarExecuting(System.Data.Common.DbCommand command, DbCommandInterceptionContext<object> interceptionContext)
        //{
        //    base.ScalarExecuting(command, interceptionContext);
        //    _stopwatch.Restart();
        //}
        //public override void ScalarExecuted(System.Data.Common.DbCommand command, DbCommandInterceptionContext<object> interceptionContext)
        //{
        //    _stopwatch.Stop();
        //    if (interceptionContext.Exception != null)
        //    {
        //        Trace.TraceError("Exception:{1} \r\n --> Error executing command: {0}", command.CommandText, interceptionContext.Exception.ToString());
        //    }
        //    else
        //    {
        //        Trace.TraceInformation("\r\n执行时间:{0} 毫秒\r\n-->ScalarExecuted.Command:{1}\r\n", _stopwatch.ElapsedMilliseconds, command.CommandText);
        //    }
        //    base.ScalarExecuted(command, interceptionContext);
        //}
        //public override void NonQueryExecuting(System.Data.Common.DbCommand command, DbCommandInterceptionContext<int> interceptionContext)
        //{
        //    base.NonQueryExecuting(command, interceptionContext);
        //    _stopwatch.Restart();
        //}
        //public override void NonQueryExecuted(System.Data.Common.DbCommand command, DbCommandInterceptionContext<int> interceptionContext)
        //{
        //    _stopwatch.Stop();
        //    if (interceptionContext.Exception != null)
        //    {
        //        Trace.TraceError("Exception:{1} \r\n --> Error executing command:\r\n {0}", command.CommandText, interceptionContext.Exception.ToString());
        //    }
        //    else
        //    {
        //        Trace.TraceInformation("\r\n执行时间:{0} 毫秒\r\n-->NonQueryExecuted.Command:\r\n{1}", _stopwatch.ElapsedMilliseconds, command.CommandText);
        //    }
        //    base.NonQueryExecuted(command, interceptionContext);
        //}
        //public override void ReaderExecuting(System.Data.Common.DbCommand command, DbCommandInterceptionContext<System.Data.Common.DbDataReader> interceptionContext)
        //{
        //    base.ReaderExecuting(command, interceptionContext);
        //    _stopwatch.Restart();
        //}
        //public override void ReaderExecuted(System.Data.Common.DbCommand command, DbCommandInterceptionContext<System.Data.Common.DbDataReader> interceptionContext)
        //{
        //    _stopwatch.Stop();

        //    var ps = command.Parameters;

        //    StringBuilder sb = new StringBuilder();

        //    foreach (DbParameter item in ps)
        //    {
        //        sb.Append(item.Value).Append(",");
        //    }

        //    if (interceptionContext.Exception != null)
        //    {
        //        Trace.TraceError("Exception:{1} \r\n --> Error executing command:\r\n {0}\r\n{2}", command.CommandText, interceptionContext.Exception.ToString(), sb.ToString().TrimEnd(','));
        //    }
        //    else
        //    {

        //        Trace.TraceInformation("\r\n执行时间:{0} 毫秒 \r\n -->ReaderExecuted.Command:\r\n{1}\r\n{2}", _stopwatch.ElapsedMilliseconds, command.CommandText, sb.ToString().TrimEnd(','));
        //    }
        //    base.ReaderExecuted(command, interceptionContext);
        //}
    }
}